package cn.tedu.tmall.admin.mall.service.impl;

import cn.tedu.tmall.admin.mall.dao.repository.IMallCategoryCacheRepository;
import cn.tedu.tmall.admin.mall.dao.repository.IMallCategoryRepository;
import cn.tedu.tmall.admin.mall.pojo.param.MallCategoryAddParam;
import cn.tedu.tmall.admin.mall.pojo.po.MallCategoryPO;
import cn.tedu.tmall.admin.mall.service.IMallCategoryService;
import cn.tedu.tmall.common.exception.ServiceException;
import cn.tedu.tmall.common.pojo.po.MallCacheCategoryPO;
import cn.tedu.tmall.common.pojo.vo.MallCategoryTreeVO;
import cn.tedu.tmall.common.web.ServiceCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * 服务层-商城分类接口实现类
 */
@Slf4j
@Service
public class MallCategoryService implements IMallCategoryService {
    @Autowired
    private IMallCategoryRepository mallCategoryRepository;

    @Autowired
    private IMallCategoryCacheRepository mallCategoryCacheRepository;

    /**
     * 简单本地缓存  https://blog.csdn.net/zzzili/article/details/131326504
     */
    private Map<String,List<MallCategoryTreeVO>> cached = new HashMap<>();

    /**
     * 新增分类业务逻辑：
     * 名称不能重复
     * 类别为顶级还是子级，父级可直接保存parentId=0，子级需要判断父级是否禁用并计算深度
     * 判断父级是否禁用
     * 计算深度：顶级：parentId=0 深度=1；子级：parentId=父级id 深度=父级深度+1
     * 计算isParent：新增一定不包含子分类，isParent=0，
     */
    @Override
    public void addCategory(MallCategoryAddParam param) {
        log.debug("Service-自增分类-入参:{}",param);
        //校验名称
        String name = param.getName();
        Integer count = mallCategoryRepository.countCategoryByName(name);
        MallCategoryPO mallCategoryPO = null;
        if (count != 0){//分类名称已存在
            log.error("Service-新增分类-名称重复:{}",name);
            throw new ServiceException(ServiceCode.FAIL.getCode(), "分类名已存在");
        }
        //判断新增分类为顶级还是子级
        Long parentId = param.getParentId();
        //为顶级，直接保存
        if (parentId == 0){
            mallCategoryPO = new MallCategoryPO();
            mallCategoryPO.setDepth(1);
            mallCategoryPO.setIsParent(0);
            BeanUtils.copyProperties(param,mallCategoryPO);
            mallCategoryRepository.save(mallCategoryPO);
            log.debug("Service-新增分类-保存顶级分类:{}",mallCategoryPO);
            return;
        }
        //为子级
        log.debug("Service-新增分类-子级-所属父级:{}",parentId);
        //获取父级分类
        MallCategoryPO parentCategoryPO = mallCategoryRepository.getParentCategoryById(parentId);
        //判断禁用选项，先不写
        //父级不存在
        if (parentCategoryPO == null){
            log.error("Service-新增分类-子级-父级不存在:{}",parentId);
            throw new ServiceException(ServiceCode.FAIL.getCode(), "该父级分类不存在");
        }
        //计算子级深度、是否为父级，保存分类
        mallCategoryPO = new MallCategoryPO();
        mallCategoryPO.setDepth(parentCategoryPO.getDepth()+1);
        mallCategoryPO.setIsParent(0);
        BeanUtils.copyProperties(param,mallCategoryPO);
        Integer rows = mallCategoryRepository.save(mallCategoryPO);
        log.debug("Service-新增分类-保存子级分类:{}",mallCategoryPO);
        //父级的isParent变为1
        if (rows == 1){
            MallCategoryPO updateCategory = new MallCategoryPO();
            updateCategory.setId(parentId);
            updateCategory.setIsParent(1);
            mallCategoryRepository.updateCategoryById(updateCategory);
            log.debug("Service-更新分类-更新父级分类:{}",mallCategoryPO);
        }
        //更新了数据库以后同时更新redis（全量更新）
        List<MallCategoryTreeVO> mallCategoryTreeVOS = treeCategory();
        mallCategoryCacheRepository.saveCategoryTree(mallCategoryTreeVOS);
        //todo 思考增量更新
        MallCacheCategoryPO mallCacheCategoryPO = new MallCacheCategoryPO();
        BeanUtils.copyProperties(mallCategoryPO,mallCacheCategoryPO);
        mallCategoryCacheRepository.saveCategoryByParentId(parentId,mallCacheCategoryPO);
    }

    /**
     * 获取分类树
     * 业务逻辑：先获取顶级分类，再递归获取子级分类，直到isParent=0
     */
    @Override
    public List<MallCategoryTreeVO> treeCategory() {
        //简单的缓存使用
        String key = "ALL";
        List<MallCategoryTreeVO> cachedVO = cached.get(key);
        if (!CollectionUtils.isEmpty(cachedVO)){
            return cachedVO;
        } else {
            //获取全部分类
            List<MallCategoryPO> allCategoryPOS = mallCategoryRepository.getAll();
            log.debug("Service-获取全部分类-all:{}",allCategoryPOS);
            //获取顶级分类
            List<MallCategoryTreeVO> topCategoryVOS = getTopCategory(allCategoryPOS);
            log.debug("Service-获取顶级分类-top:{}",topCategoryVOS);
            //获取子级分类
            for (MallCategoryTreeVO topCategoryVO : topCategoryVOS) {
                getChildCategory(topCategoryVO,allCategoryPOS);
            }
            return topCategoryVOS;
        }
    }

    /**
     * 延迟加载策略-获取顶级分类树
     */
    @Override
    public List<MallCategoryTreeVO> treeTopCategory() {
        List<MallCategoryPO> topCategoryPOS = mallCategoryRepository.getTopCategory();
        List<MallCategoryTreeVO> topCategoryVOS = categoryPOS2VOS(topCategoryPOS);
        log.debug("Service-获取顶级分类-top:{}",topCategoryVOS);
        return topCategoryVOS;
    }

    /**
     * 延迟加载策略-获取子级分类树
     */
    @Override
    public List<MallCategoryTreeVO> treeChildrenCategory(Long parentId) {
        List<MallCategoryPO> childrenCategoryPOS = mallCategoryRepository.getChildrenCategory(parentId);
        List<MallCategoryTreeVO> childrenCategoryVOS = categoryPOS2VOS(childrenCategoryPOS);
        log.debug("Service-获取顶级分类-top:{}",childrenCategoryVOS);
        return childrenCategoryVOS;
    }

    /**
     * 获取顶级分类
     * @param categoryPOS 所有分类
     * @return List<MallCategoryPO> topCategory
     */
    private List<MallCategoryTreeVO> getTopCategory(List<MallCategoryPO> categoryPOS){
        List<MallCategoryTreeVO> topCategory = new ArrayList<>();
        for (MallCategoryPO po : categoryPOS) {
            if (po.getParentId() == 0)
                topCategory.add(categoryPO2VO(po));
        }
        return topCategory;
    }

    /**
     * categoryPO转换为VO
     */
    private MallCategoryTreeVO categoryPO2VO(MallCategoryPO po){
        MallCategoryTreeVO vo = new MallCategoryTreeVO();
        BeanUtils.copyProperties(po,vo);
        return vo;
    }

    /**
     * categoryPO集合转换为VO集合
     */
    private List<MallCategoryTreeVO> categoryPOS2VOS(List<MallCategoryPO> categoryPOS){
        List<MallCategoryTreeVO> list = new ArrayList<>();
        for (MallCategoryPO categoryPO : categoryPOS) {
            list.add(categoryPO2VO(categoryPO));
        }
        return list;
    }

    /**
     * 获取子级分类
     */
    private MallCategoryTreeVO getChildCategory(MallCategoryTreeVO vo,List<MallCategoryPO> all){
        List<MallCategoryTreeVO> childrenCategory = new ArrayList<>();
        for (MallCategoryPO po : all) {
            if (vo.getId().equals(po.getParentId())){
                MallCategoryTreeVO childVO = categoryPO2VO(po);
                childrenCategory.add(getChildCategory(childVO,all));
            } else {
                //直到isParent=0, 退出循环
            }
        }
        vo.setChildren(childrenCategory);
        return vo;
    }

}
